package ru.susu.algebra.centralunits.alternating.tex.local;

import java.math.BigInteger;

import ru.susu.algebra.centralunits.alternating.initializers.BetaInitializer;
import ru.susu.algebra.centralunits.alternating.initializers.QuadraticFieldsInitializer;
import ru.susu.algebra.centralunits.alternating.initializers.SpecialRowsInitializer;
import ru.susu.algebra.centralunits.alternating.tex.SpecialCharactersUnionMathMethod;
import ru.susu.algebra.chartable.constructor.AlternatingCharTableUtil;
import ru.susu.algebra.field.quadratic.QuadraticField;
import ru.susu.algebra.field.quadratic.QuadraticFieldGeneralForm;
import ru.susu.algebra.field.quadratic.QuadraticInteger;
import ru.susu.algebra.jtex.ITexElement;
import ru.susu.algebra.jtex.ITexSubItemsElement;
import ru.susu.algebra.jtex.SimpleTexElementWithCode;
import ru.susu.algebra.jtex.StringTexElement;
import ru.susu.algebra.jtex.TexBeginEndElement;
import ru.susu.algebra.jtex.UnionTexElement;
import ru.susu.algebra.jtex.formula.FormulaTexElement;
import ru.susu.algebra.jtex.formula.GreekSymbols;
import ru.susu.algebra.jtex.formula.MathSymbols;
import ru.susu.algebra.jtex.utils.TexUtils;
import ru.susu.algebra.partition.Partition;
import ru.susu.algebra.properties.IPropertySource;
import ru.susu.algebra.util.NumberUtilities;

/**
 * @author akargapolov
 * @since: 08.09.2010
 */
public class DivisibilityLemma extends SpecialCharactersUnionMathMethod
{
	private static final Class[] DEPENDENCIES = {SpecialRowsInitializer.class, QuadraticFieldsInitializer.class, BetaInitializer.class};

	public static String getLabelName(Partition partition, IPropertySource ps)
	{
		Integer number = SpecialRowsInitializer.getRowNumber(ps, partition);
		return "divisibility" + number;
	}

	public static BigInteger getMod4LocalUnit(IPropertySource ps, Partition partition)
	{
		QuadraticInteger character = QuadraticFieldsInitializer.getCharacter(ps, partition);
		return AlternatingCharTableUtil.calcZX(partition).divide(character.getB()).divide(character.getD());
	}

	@Override
	protected ITexElement getElement(Partition partition, IPropertySource ps) throws Exception
	{
		String alphaM1 = GreekSymbols.ALPHA + " - 1";
		String alphaM1Brackets = TexUtils.inBrackets(alphaM1);
		Integer rowNumber = SpecialRowsInitializer.getRowNumber(ps, partition);
		QuadraticField field = QuadraticFieldsInitializer.getRow2Field(ps).get(partition);
		QuadraticInteger generateInteger = field.getGenerateInteger();
		QuadraticInteger character1 = QuadraticFieldsInitializer.getCharacter(ps, partition);
		QuadraticInteger character2 = character1.getConjugateNumber();
		String aNumber = "A" + TexUtils.index(rowNumber);
		String doubleSlash = "," + MathSymbols.DOUBLE_INV_SLASH + "\n";
		BigInteger sqrtNumber = field.getGenerateInteger().getD();
		String omegaWithIndex = GreekSymbols.OMEGA + TexUtils.index(sqrtNumber);
		QuadraticFieldGeneralForm omega = QuadraticFieldsInitializer.getOmega(ps, partition);
		QuadraticFieldGeneralForm conjugateOmega = (QuadraticFieldGeneralForm)omega.getConjugateNumber();
		QuadraticFieldGeneralForm omega2 = (QuadraticFieldGeneralForm)omega.pow(BigInteger.valueOf(2));
		String lambdaM1Brackets = TexUtils.inBrackets(GreekSymbols.LAMBDA + " - 1");
		BigInteger beta1 = BetaInitializer.getBetaCoefficient(ps, partition, character1);
		BigInteger beta2 = BetaInitializer.getBetaCoefficient(ps, partition, character2);
		BigInteger zChi = AlternatingCharTableUtil.calcZX(partition);
		String zWithIndex = "z" + TexUtils.index(rowNumber);
		String zChiFactorization = TexUtils.getFactorization(zChi);
		String localUnitInCentralUnitsGroup = "$u" + TexUtils.index(rowNumber) + TexUtils.inBrackets(GreekSymbols.LAMBDA) + MathSymbols.IN + "\\Un" +
			TexUtils.inBrackets("Z" + TexUtils.inBrackets("\\Z A" + TexUtils.index(partition.getPresentedNumber()))) + "$"; //$u_{20}(\lambda)\in\Un(Z(\Z A_{14}))$

		BigInteger betaSum = beta1.subtract(beta2).abs();
		BigInteger bd = character1.getB().multiply(character1.getD()).abs();
		BigInteger beta3 = bd.subtract(BigInteger.valueOf(2)).multiply(beta1).add(BigInteger.ONE);
		String beta3TF = NumberUtilities.toString(beta3, true, false);
		if (!bd.equals(betaSum) || !beta3.remainder(bd).equals(BigInteger.ZERO))
		{
			throw new RuntimeException("DivisibilityLemma: bd = " + bd + " betaSum = " + betaSum + " beta3 = " + beta3);
		}

		if (!zChi.remainder(bd).equals(BigInteger.ZERO))
		{
			throw new RuntimeException("Z not divides by BD");
		}
		BigInteger zDivided = zChi.divide(bd);


	/*	\begin{lemma}\label{dz20}
		Пусть $\lambda=\alpha+\beta\omega_{13}$. Локальная единица
		$u_{20}(\lambda)\in\Un(Z(\Z A_{14}))$ тогда и только тогда, когда
		\begin{equation}
		\left\{\begin{aligned}
		9172800&\text{ делит }\alpha-1,\\
		9172800&\text{ делит }\beta.
		\end{aligned}\right.
		\end{equation} */
		ITexSubItemsElement lemma = TexBeginEndElement.lemma().addSubElement(SimpleTexElementWithCode.label(getLabelName(partition, ps)));
		lemma.addSubElement(StringTexElement.text(
				"Пусть $" + GreekSymbols.LAMBDA + " = " + GreekSymbols.ALPHA + MathSymbols.PLUS + GreekSymbols.BETA + omegaWithIndex + "$. " +
				"Локальная единица\n" +
				localUnitInCentralUnitsGroup + " тогда и только тогда, когда\n")).addSubElement(TexBeginEndElement.equation().addSubElement(StringTexElement.text(
						MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
						zDivided + "&" + SimpleTexElementWithCode.text(" делит ") + alphaM1 + doubleSlash +
						zDivided + "&" + SimpleTexElementWithCode.text(" делит ") + GreekSymbols.BETA + "."))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + ".")));

	/* По-другому $u_{20}(\lambda)\in\Un(Z(\Z A_{14}))$ тогда и только тогда, когда
		\begin{equation}
		\lambda\in1+z\Z[\omega_{13}].
		\end{equation}
		\end{lemma} */
		lemma.addSubElement(StringTexElement.text(
				"По-другому " + localUnitInCentralUnitsGroup + " тогда и только тогда, когда\n")).addSubElement(TexBeginEndElement.equation().addSubElement(StringTexElement.text(
				GreekSymbols.LAMBDA + MathSymbols.IN + "1+z\\Z[" + omegaWithIndex + "].")));

	/* \begin{proof}
		Нужно, чтобы $\gamma_i$ для всех $i$ были целыми. Из вида двадцатой строчки таблицы характеров следует, что нам будут интересны
		\begin{equation}
		\left\{\begin{aligned}
		\frac{\tr(\lambda-1)}{z_{20}}&=\frac{\tr(\lambda-1)}{2^6\cdot3^2\cdot5^2\cdot7^2\cdot13}=
		\frac{\tr(\lambda-1)}{9172800},\\
		\frac{\tr(\texttt{A}(\lambda-1))}{z_{20}}&=\frac{\tr(\texttt{A}(\lambda-1))}{2^6\cdot3^2\cdot5^2\cdot7^2\cdot13}=
		\frac{\tr(\texttt{A}(\lambda-1))}{9172800},\\
		\frac{\tr(\texttt{*A}(\lambda-1))}{z_{20}}&=\frac{\tr(\texttt{*A}(\lambda-1))}{2^6\cdot3^2\cdot5^2\cdot7^2\cdot13}=
		\frac{\tr(\texttt{*A}(\lambda-1))}{9172800}.
		\end{aligned}\right.
		\end{equation} */
		ITexSubItemsElement proof = TexBeginEndElement.proof();
		proof.addSubElement(StringTexElement.text(
				"Нужно, чтобы $" + GreekSymbols.GAMMA + TexUtils.index("i") + "$ для всех $i$ были целыми. Из вида " + rowNumber + "-ой строчки таблицы характеров следует," +
				"что нам будут интересны")).addSubElement(TexBeginEndElement.equation().addSubElement(StringTexElement.text(
				MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				FormulaTexElement.frac(MathSymbols.TR + lambdaM1Brackets, zWithIndex) + "&=" +
				FormulaTexElement.frac(MathSymbols.TR + lambdaM1Brackets, zChiFactorization) + "=\n" +
				FormulaTexElement.frac(MathSymbols.TR + lambdaM1Brackets, zChi.toString()) + doubleSlash +

				FormulaTexElement.frac(MathSymbols.TR + TexUtils.inBrackets("A" + lambdaM1Brackets), zWithIndex) + "&=" +
				FormulaTexElement.frac(MathSymbols.TR + TexUtils.inBrackets("A" + lambdaM1Brackets), zChiFactorization) + "=\n" +
				FormulaTexElement.frac(MathSymbols.TR + TexUtils.inBrackets("A" + lambdaM1Brackets), zChi.toString()) + doubleSlash +

				FormulaTexElement.frac(MathSymbols.TR + TexUtils.inBrackets("*A" + lambdaM1Brackets), zWithIndex) + "&=" +
				FormulaTexElement.frac(MathSymbols.TR + TexUtils.inBrackets("*A" + lambdaM1Brackets), zChiFactorization) + "=\n" +
				FormulaTexElement.frac(MathSymbols.TR + TexUtils.inBrackets("*A" + lambdaM1Brackets), zChi.toString())))).addSubElement(StringTexElement.text(
				MathSymbols.RIGHT + ".")));

		String beta1TF = NumberUtilities.toString(beta1, true, false);
		String beta2TF = NumberUtilities.toString(beta2, true, false);
		TexBeginEndElement align = TexBeginEndElement.align().setWithoutNumber();
		proof.addSubElement(StringTexElement.text("Таким образом надо, чтобы")).addSubElement(align);

		String line1 = zChi + "&" + MathSymbols.MID + "2" + alphaM1Brackets + MathSymbols.PLUS + GreekSymbols.BETA;
		String line2 = zChi + "&" + MathSymbols.MID + alphaM1Brackets + beta1TF + GreekSymbols.BETA;
		String line3 = zChi + "&" + MathSymbols.MID + alphaM1Brackets + beta2TF + GreekSymbols.BETA;

	/* Таким образом надо, чтобы
		\begin{align*}
		\left\{\begin{aligned}
		9172800&\mid 2(\alpha-1)+\beta\\
		9172800&\mid (\alpha-1)-6\beta\\
		9172800&\mid (\alpha-1)+7\beta
		\end{aligned}\right.&\iff */
		align.addSubElement(StringTexElement.text(
				MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				line1 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line2 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line3))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + ".&" + MathSymbols.IFF));

	/* \left\{\begin{aligned}
		9172800&\mid 2(\alpha-1)+\beta\\
		9172800&\mid (\alpha-1)-6\beta\\
		9172800&\mid (\alpha-1)+7\beta
		\end{aligned}\right.\iff\\ */
		align.addSubElement(StringTexElement.text(
				MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				line1 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line2 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line3))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + ".&" + MathSymbols.IFF + MathSymbols.DOUBLE_INV_SLASH + "\n"));

	/* &\iff\left\{\begin{aligned}
		9172800&\mid 2(\alpha-1)+\beta\\
		9172800&\mid (\alpha-1)-6\beta\\
		9172800&\mid (\alpha-1)+7\beta\\
		9172800&\mid -13\beta
		\end{aligned}\right.\iff\\ */
		align.addSubElement(StringTexElement.text(
				"&" + MathSymbols.IFF + MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				line1 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line2 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line3 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				zChi + "&" + MathSymbols.MID + bd + GreekSymbols.BETA))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + ".&" + MathSymbols.IFF + MathSymbols.DOUBLE_INV_SLASH + "\n"));

	/* &\iff\left\{\begin{aligned}
		9172800&\mid bd(\alpha-1)+beta3\beta\\
		9172800&\mid (\alpha-1)-6\beta\\
		9172800&\mid (\alpha-1)+7\beta\\
		9172800&\mid -13\beta
		\end{aligned}\right.\iff\\ */
		align.addSubElement(StringTexElement.text(
				"&" + MathSymbols.IFF + MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				zChi + "&" + MathSymbols.MID + bd + alphaM1Brackets + beta3TF + GreekSymbols.BETA + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line2 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line3 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				zChi + "&" + MathSymbols.MID + bd + GreekSymbols.BETA))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + ".&" + MathSymbols.IFF + MathSymbols.DOUBLE_INV_SLASH + "\n"));

	/* &\iff\left\{\begin{aligned}
		9172800&\mid bd(\alpha-1)\\
		9172800&\mid (\alpha-1)-6\beta\\
		9172800&\mid (\alpha-1)+7\beta\\
		9172800&\mid -13\beta
		\end{aligned}\right.\iff\\ */
		align.addSubElement(StringTexElement.text(
				"&" + MathSymbols.IFF + MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				zChi + "&" + MathSymbols.MID + bd + alphaM1Brackets + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line2 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				line3 + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				zChi + "&" + MathSymbols.MID + bd + GreekSymbols.BETA))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + ".&" + MathSymbols.IFF + MathSymbols.DOUBLE_INV_SLASH + "\n"));

	/* &\iff\left\{\begin{aligned}
	 	zDivided&\mid (\alpha-1)\\
	 	zDivided&\mid \beta
		\end{aligned}\right. */
		align.addSubElement(StringTexElement.text(
				"&" + MathSymbols.IFF + MathSymbols.LEFT + "\\{")).addSubElement(TexBeginEndElement.aligned().addSubElement(StringTexElement.text(
				zDivided + "&" + MathSymbols.MID + alphaM1Brackets + MathSymbols.DOUBLE_INV_SLASH + "\n" +
				zDivided + "&" + MathSymbols.MID + GreekSymbols.BETA))).addSubElement(StringTexElement.text(
						MathSymbols.RIGHT + "."));

		return new UnionTexElement().addSubElement(lemma).addSubElement(proof);
	}

	@Override
	protected Class[] getDependentInitializers()
	{
		return DEPENDENCIES;
	}
}
